#include "OGLShaderObject.h"
#include "types.h"

#include <glog/logging.h>
#include <algorithm>

using namespace google;

namespace Hope{

    OGLShaderObject::OGLShaderObject(const char * vertexShader, const char * fragmentShader)
    {
        init(vertexShader, fragmentShader);
    }

    OGLShaderObject::~OGLShaderObject()
    {
        if (m_program)
        {
            GLuint shaders[8];
            GLint count;
            glGetAttachedShaders(m_program, 8, &count, shaders);
            int minCount = std::min(count, 8);
            for (int i = 0; i < minCount; ++i)
            {
                glDeleteShader(shaders[i]);
            }
            glDeleteProgram(m_program);
            m_program = 0;
        }
    }

    void OGLShaderObject::init(const char * vertexShader, const char * fragmentShader)
    {
        if (!createProgram())
        {
            return;
        }

        if (!createShader(GL_VERTEX_SHADER, vertexShader))
        {
            return;
        }

        if (!createShader(GL_FRAGMENT_SHADER, fragmentShader))
        {
            return;
        }
        
        if (!linkProgram())
        {
            return;
        }
    }

    bool OGLShaderObject::createProgram()
    {
        m_program = glCreateProgram();
        return true;
    }

    bool OGLShaderObject::linkProgram()
    {
        if (!m_program)
        {
            return false;
        }

        GLint success;
        glLinkProgram(m_program);
        glGetProgramiv(m_program, GL_LINK_STATUS, &success);
        if (!success)
        {
            GLchar info[1024];
            GLsizei length;
            glGetProgramInfoLog(m_program, 1024, &length, info);
            LOG(ERROR) << "shader link error:" << info;
            return false;
        }

        return true;
    }

    bool OGLShaderObject::createShader(GLenum type, const char * shader)
    {
        if (m_program)
        {
            GLchar info[1024];
            GLint success;
            GLuint shader_object = glCreateShader(type);
            glShaderSource(shader_object, strlen(shader), &shader, NULL);
            glCompileShader(shader_object);
            glGetShaderiv(shader_object, GL_COMPILE_STATUS, &success);
            if (!success)
            {
                glGetShaderInfoLog(shader_object, 1024, NULL, info);
                LOG(ERROR) << "compile fragment shader, error:" << info;
                return false;
            }

            glAttachShader(m_program, shader_object);
            return true;
        }

        return false;
    }

}